package com.tanhua.management.service;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.management.enums.AreaEnum;
import com.tanhua.management.mapper.LogMapper;
import com.tanhua.management.mapper.UserInfoMapper;
import com.tanhua.management.mapper.UsersMapper;
import com.tanhua.management.pojo.Log;
import com.tanhua.management.pojo.User;
import com.tanhua.management.pojo.UserInfo;
import com.tanhua.management.vo.DateVo;
import com.tanhua.management.vo.DistributionVo;
import com.tanhua.management.vo.SummaryVo;
import com.tanhua.management.vo.UsersStatisticsVo;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @Author: LY
 * @Description:
 * @Date: Created in 10:35 2021/1/17
 * @ModifiedBy:
 */
@Service
public class DashBoardService {

    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private LogMapper logMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    private Date NOW = new Date(System.currentTimeMillis());

    /**
     * 概要统计信息
     *
     * @return
     */
    public ResponseEntity<SummaryVo> getSummary() {
        try {
            SummaryVo summaryVo = new SummaryVo();

            //累计用户数
            Integer integerCount = this.usersMapper.selectCount(null);
            summaryVo.setCumulativeUsers(integerCount);

            //过去30天活跃用户
            QueryWrapper<Log> monthQuery = new QueryWrapper<>();
            monthQuery.between("log_time", DateUtil.beginOfMonth(NOW), NOW);
            Integer integerMonthLogin = this.logMapper.selectCount(monthQuery);
            summaryVo.setActivePassMonth(integerMonthLogin);

            //过去7天活跃用户
            QueryWrapper<Log> weekQuery = new QueryWrapper<>();
            weekQuery.between("log_time", DateUtil.beginOfWeek(NOW), NOW);
            Integer integerWeekLogin = this.logMapper.selectCount(weekQuery);
            summaryVo.setActivePassWeek(integerWeekLogin);

            //今日新增用户
            List<UserInfo> userInfostoday = this.userInfoMapper.selectList(null);
            int todayCount = 0;
            for (UserInfo userInfo : userInfostoday) {
                Date created = userInfo.getCreated();
                long time = created.getTime();
                if (time >= DateUtil.beginOfDay(NOW).getTime() && time <= NOW.getTime()) {
                    todayCount++;
                }
            }
            summaryVo.setNewUsersToday(todayCount);

            //昨日新增用户
            List<UserInfo> userInfosYestday = this.userInfoMapper.selectList(null);
            int yestdayCount = 0;
            for (UserInfo userInfo : userInfosYestday) {
                Date created = userInfo.getCreated();
                long time = created.getTime();
                if (time >= DateUtil.beginOfDay(DateUtil.yesterday()).getTime() && time <= DateUtil.beginOfDay(NOW).getTime()) {
                    yestdayCount++;
                }
            }

            //今日活跃用户/今日登录次数
            QueryWrapper<Log> todayQuery = new QueryWrapper<>();
            todayQuery.between("log_time", DateUtil.beginOfDay(NOW), NOW);
            Integer integerTodayLogin = this.logMapper.selectCount(todayQuery);
            summaryVo.setActiveUsersToday(integerTodayLogin);
            summaryVo.setLoginTimesToday(integerTodayLogin);

            //过去7天平均日使用时长，单位秒，没有数据，塞个随机数算球
            summaryVo.setUseTimePassWeek(RandomUtils.nextInt(0, 86400));

            //昨日活跃用户/昨日登录次数
            QueryWrapper<Log> yestdayQuery = new QueryWrapper<>();
            yestdayQuery.between("log_time", DateUtil.beginOfDay(DateUtil.yesterday()), DateUtil.beginOfDay(NOW));
            Integer integerYestdayLogin = this.logMapper.selectCount(yestdayQuery);
            summaryVo.setActiveUsersYesterday(integerYestdayLogin);

            //前天活跃用户/前天登录次数
            QueryWrapper<Log> dBYestdayQuery = new QueryWrapper<>();
            dBYestdayQuery.between("log_time", DateUtil.offsetDay(DateUtil.beginOfDay(NOW), -2), DateUtil.offsetDay(DateUtil.beginOfDay(NOW), -1));
            Integer integerToToLogin = this.logMapper.selectCount(dBYestdayQuery);

            //今日新增用户涨跌率，单位百分数，正数为涨，负数为跌
            int insert = 0;
            if (yestdayCount == 0) {
                insert = (todayCount);
            } else {
                insert = (todayCount - yestdayCount) / yestdayCount;
            }
            summaryVo.setNewUsersTodayRate(insert);

            //今日活跃用户涨跌率，单位百分数，正数为涨，负数为跌
            int up = 0;
            up = (integerTodayLogin - integerYestdayLogin);
            summaryVo.setActiveUsersTodayRate(up);

            //昨日活跃用户涨跌率，单位百分数，正数为涨，负数为跌
            int yestdayUp = 0;
            yestdayUp = (integerToToLogin - integerYestdayLogin);
            summaryVo.setActiveUsersYesterdayRate(yestdayUp);

            //今日登录次数涨跌率，单位百分数，正数为涨，负数为跌
            summaryVo.setLoginTimesTodayRate(up);

            return ResponseEntity.ok(summaryVo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
    }

    /**
     * 新增、活跃用户、次日留存率
     *
     * @param sd
     * @param ed
     * @param type
     * @return
     */
    public ResponseEntity<UsersStatisticsVo> getUsers(Long sd, Long ed, Integer type) {
        try {
            switch (type) {
                case 101://新增
                    return this.getNews(sd, ed);
                case 102://活跃
                    return this.getActive(sd, ed);
                case 103://次日留存率
                    return this.nextDay(sd, ed);
                default:
                    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
    }

    /**
     * 次日留存率
     *
     * @param sd
     * @param ed
     * @return
     */
    private ResponseEntity<UsersStatisticsVo> nextDay(Long sd, Long ed) {
        UsersStatisticsVo usersStatisticsVo = new UsersStatisticsVo();
        List<DateVo> thisYear = new ArrayList<>();//今年用户集合
        List<DateVo> lastYear = new ArrayList<>();//去年用户集合

        Date sdTime = DateUtil.offset(new Date(sd), DateField.YEAR, -1); // 去年开始时间
        Date edTime = DateUtil.offset(new Date(ed), DateField.YEAR, -1); // 去年结束时间

        List<Log> logList = logMapper.selectList(null);
        List<User> userList = usersMapper.selectList(null);//全部的用户的集合

        List<User> thisUserList = new ArrayList<>();
        List<User> lastUserList = new ArrayList<>();

        for (User user : userList) {
            long time = user.getCreated().getTime();
            if (time >= sd && time <= ed) {
                Long stime = DateUtil.beginOfDay(DateUtil.date(time)).getTime() + 24 * 60 * 60;
                Long etime = DateUtil.endOfDay(DateUtil.date(time)).getTime() + 24 * 60 * 60;
                for (Log log : logList) {
                    Long logTime = log.getLogTime().getTime();
                    if (logTime >= stime && logTime <= etime) {
                        thisUserList.add(user);
                        break;
                    }
                }
            }
        }

        long t = 0;//计数器
        for (int i = 1; i <= 12; i++) {
            for (User user : thisUserList) {
                int month = DateUtil.month(user.getCreated());
                if ((month + 1) == i) {
                    t += 1;
                }
            }
            DateVo dateVo = new DateVo(String.valueOf(i), t);
            thisYear.add(dateVo);
        }

        for (User user : userList) {
            long time = user.getCreated().getTime();
            if (time >= sdTime.getTime() && time <= edTime.getTime()) {
                Long stime = DateUtil.beginOfDay(DateUtil.date(time)).getTime() + 24 * 60 * 60;
                Long etime = DateUtil.endOfDay(DateUtil.date(time)).getTime() + 24 * 60 * 60;
                for (Log log : logList) {
                    Long logTime = log.getLogTime().getTime();
                    if (logTime >= stime && logTime <= etime) {
                        lastUserList.add(user);
                        break;
                    }
                }
            }
        }

        long e = 0;//计数器
        for (int i = 1; i <= 12; i++) {
            for (User user : lastUserList) {
                int month = DateUtil.month(user.getCreated());
                if ((month + 1) == i) {
                    e += 1;
                }
            }
            DateVo dateVo = new DateVo(String.valueOf(i), e);
            lastYear.add(dateVo);
        }

        usersStatisticsVo.setThisYear(thisYear);
        usersStatisticsVo.setLastYear(lastYear);
        return ResponseEntity.ok(usersStatisticsVo);
    }

    /**
     * 活跃用户
     *
     * @param sd
     * @param ed
     * @return
     */
    private ResponseEntity<UsersStatisticsVo> getActive(Long sd, Long ed) {
        UsersStatisticsVo usersStatisticsVo = new UsersStatisticsVo();
        List<DateVo> thisYear = new ArrayList<>();//今年用户集合
        List<DateVo> lastYear = new ArrayList<>();//去年用户集合

        Date sdTime = DateUtil.offset(new Date(sd), DateField.YEAR, -1); // 去年开始时间
        Date edTime = DateUtil.offset(new Date(ed), DateField.YEAR, -1); // 去年结束时间

        List<Log> logList = logMapper.selectList(null);
        List<Log> thisList = new ArrayList<>();

        for (Log log : logList) {
            long time = log.getLogTime().getTime();
            if (time >= sd && time <= ed) {
                thisList.add(log);
            }
        }

        long t = 0;//计数器
        for (int i = 1; i <= 12; i++) {
            for (Log log : thisList) {
                int month = DateUtil.month(new Date(log.getLogTime().getTime()));
                if ((month + 1) == i) {
                    t += 1;
                }
            }
            DateVo dateVo = new DateVo(String.valueOf(i), t);
            thisYear.add(dateVo);
        }

        List<Log> lastList = new ArrayList<>();//今年新增用户集合

        for (Log log : logList) {
            long time = log.getLogTime().getTime();
            if (time >= sdTime.getTime() && time <= edTime.getTime()) {
                lastList.add(log);
            }
        }

        long l = 0;//计数器
        for (int i = 1; i <= 12; i++) {
            for (Log log : lastList) {
                int month = DateUtil.month(new Date(log.getLogTime().getTime()));
                if ((month + 1) == i) {
                    l += 1;
                }
            }
            DateVo dateVo = new DateVo(String.valueOf(i), l);
            lastYear.add(dateVo);
        }

        usersStatisticsVo.setThisYear(thisYear);
        usersStatisticsVo.setLastYear(lastYear);
        return ResponseEntity.ok(usersStatisticsVo);
    }

    /**
     * 新增用户
     *
     * @param sd
     * @param ed
     * @return
     */
    private ResponseEntity<UsersStatisticsVo> getNews(Long sd, Long ed) {
        UsersStatisticsVo usersStatisticsVo = new UsersStatisticsVo();
        List<DateVo> thisYear = new ArrayList<>();//今年用户集合
        List<DateVo> lastYear = new ArrayList<>();//去年用户集合

        Date sdTime = DateUtil.offset(new Date(sd), DateField.YEAR, -1); // 去年开始时间
        Date edTime = DateUtil.offset(new Date(ed), DateField.YEAR, -1); // 去年结束时间

        List<User> userList = usersMapper.selectList(null);//全部的用户的集合
        List<User> thisList = new ArrayList<>();//今年新增用户集合

        for (User user : userList) {
            long time = user.getCreated().getTime();
            if (time >= sd && time <= ed) {
                thisList.add(user);
            }
        }

        long t = 0;//计数器
        for (int i = 1; i <= 12; i++) {
            for (User user : thisList) {
                int month = DateUtil.month(user.getCreated());
                if ((month + 1) == i) {
                    t += 1;
                }
            }
            DateVo dateVo = new DateVo(String.valueOf(i), t);
            thisYear.add(dateVo);
        }

        List<User> lastList = new ArrayList<>();//今年新增用户集合

        for (User user : userList) {
            long time = user.getCreated().getTime();
            if (time >= sdTime.getTime() && time <= edTime.getTime()) {
                lastList.add(user);
            }
        }

        long l = 0;//计数器
        for (int i = 1; i <= 12; i++) {
            for (User user : lastList) {
                int month = DateUtil.month(user.getCreated());
                if ((month + 1) == i) {
                    l += 1;
                }
            }
            DateVo dateVo = new DateVo(String.valueOf(i), l);
            lastYear.add(dateVo);
        }

        usersStatisticsVo.setThisYear(thisYear);
        usersStatisticsVo.setLastYear(lastYear);
        return ResponseEntity.ok(usersStatisticsVo);
    }

    /**
     * 注册用户分布，行业top、年龄、性别、地区
     *
     * @param sd
     * @param ed
     * @return
     */
    public ResponseEntity<DistributionVo> getDistribution(Long sd, Long ed) {
        try {
            DistributionVo distributionVo = new DistributionVo();

            List<UserInfo> userInfoList = userInfoMapper.selectList(null);//全部的用户的集合
            List<UserInfo> newList = new ArrayList<>();

            //newList里是符合时间条件的用户
            for (UserInfo userInfo : userInfoList) {
                long time = userInfo.getCreated().getTime();
                if (time >= sd && time <= ed) {
                    newList.add(userInfo);
                }
            }

            Map<String, Integer> map = new HashMap<>();
            for (UserInfo userInfo : newList) {
                String industry = userInfo.getIndustry();
                if (!map.containsKey(industry)) {
                    map.put(industry, 1);
                } else {
                    map.put(industry, map.get(industry) + 1);
                }
            }
            List<DateVo> industryDistribution = new ArrayList<>();//行业分布
            for (String key : map.keySet()) {
                DateVo dateVo = new DateVo();
                dateVo.setTitle(key);
                dateVo.setAmount((long) map.get(key));
                industryDistribution.add(dateVo);
            }

            industryDistribution.sort((o1, o2) -> Integer.parseInt(String.valueOf(o2.getAmount() - o1.getAmount())));

            map.clear();
            map.put("0-17岁", 0);
            map.put("18-23岁", 0);
            map.put("24-30岁", 0);
            map.put("31-40岁", 0);
            map.put("41-50岁", 0);
            map.put("50+岁", 0);
            for (UserInfo userInfo : newList) {
                Integer age = userInfo.getAge();
                if (age <= 17) {
                    map.put("0-17岁", map.get("0-17岁") + 1);
                }
                if (age >= 18 && age <= 23) {
                    map.put("18-23岁", map.get("18-23岁") + 1);
                }
                if (age >= 24 && age <= 30) {
                    map.put("24-30岁", map.get("24-30岁") + 1);
                }
                if (age >= 31 && age <= 40) {
                    map.put("31-40岁", map.get("31-40岁") + 1);
                }
                if (age >= 41 && age <= 50) {
                    map.put("41-50岁", map.get("41-50岁") + 1);
                }
                if (age >= 51) {
                    map.put("50+岁", map.get("50+岁") + 1);
                }
            }
            List<DateVo> ageDistribution = new ArrayList<>();//年龄分布
            for (String key : map.keySet()) {
                DateVo dateVo = new DateVo();
                dateVo.setTitle(key);
                dateVo.setAmount((long) map.get(key));
                ageDistribution.add(dateVo);
            }

            map.clear();
            map.put("男", 0);
            map.put("女", 0);
            for (UserInfo userInfo : newList) {
                Integer gender = userInfo.getSex();
                if (gender == 1) {
                    map.put("男", map.get("男") + 1);
                }
                if (gender == 2) {
                    map.put("女", map.get("女") + 1);
                }
            }
            List<DateVo> genderDistribution = new ArrayList<>();
            for (String key : map.keySet()) {
                DateVo dateVo = new DateVo();
                dateVo.setTitle(key);
                dateVo.setAmount((long) map.get(key));
                genderDistribution.add(dateVo);
            }

            map.clear();
            Map<String, Integer> areaMap = new HashMap<>();
            for (UserInfo userInfo : newList) {
                String citys = userInfo.getCity();
                String city = citys.split("-")[0];
                String area = AreaEnum.getAreaByProvince(city);
                if (!map.containsKey(city)) {
                    map.put(city, 1);
                } else {
                    map.put(city, map.get(city) + 1);
                }
                if (!areaMap.containsKey(area)) {
                    areaMap.put(area, 1);
                } else {
                    areaMap.put(area, areaMap.get(area) + 1);
                }
            }
            List<DateVo> localDistribution = new ArrayList<>();
            for (String key : map.keySet()) {
                DateVo dateVo = new DateVo();
                dateVo.setTitle(key);
                dateVo.setAmount((long) map.get(key));
                localDistribution.add(dateVo);
            }
            List<DateVo> localTotal = new ArrayList<>();
            for (String key : areaMap.keySet()) {
                DateVo dateVo = new DateVo();
                dateVo.setTitle(key);
                dateVo.setAmount((long) areaMap.get(key));
                localTotal.add(dateVo);
            }

            distributionVo.setIndustryDistribution(industryDistribution);
            distributionVo.setAgeDistribution(ageDistribution);
            distributionVo.setGenderDistribution(genderDistribution);
            distributionVo.setLocalDistribution(localDistribution);
            distributionVo.setLocalTotal(localTotal);

            return ResponseEntity.ok(distributionVo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
    }
}
